package com.crawler.gmail.crawler;

import com.crawler.gmail.enums.ChannelTypeEnum;
import com.crawler.gmail.enums.FileTypeEnum;
import com.crawler.gmail.enums.MailProtocolEnum;
import com.crawler.gmail.utils.JsonUtil;
import com.crawler.gmail.utils.OssFile;
import com.sun.mail.imap.IMAPStore;
import org.apache.commons.io.FileUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.mozilla.universalchardet.UniversalDetector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.lang3.StringUtils;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <描述>
 * <详细介绍>
 *
 * @author 王明明
 * @since wiki
 */
public class EmailCrawler {
    private final static Logger LOGGER = LoggerFactory.getLogger(EmailCrawler.class);
    // 登录邮箱
    private final String username;
    // 密码
    private final String password;
    // 最后抓取时间
    private final Long lastFetchTime;
    // 协议
    private final Integer protocol;
    private EmailFetchSettingDO emailFetchSettingDO;


    private final static SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z", Locale.US);
    private final static SimpleDateFormat sdf2 = new SimpleDateFormat("MMM dd yyyy HH:mm:ss z", Locale.US);


    public EmailCrawler(EmailFetchSettingDO emailFetchSettingDO) {
        this.lastFetchTime = emailFetchSettingDO.getLastFetchTime();
        this.username = emailFetchSettingDO.getUsername();
        this.password = emailFetchSettingDO.getPassword();
        this.protocol = emailFetchSettingDO.getProtocol();
        this.emailFetchSettingDO = emailFetchSettingDO;
    }

    public void fetchAllEmail(Store store) throws MessagingException {
        Folder defaultFolder = store.getDefaultFolder();
        getAllFolders(defaultFolder);
    }

    public void getAllFolders(Folder defaultFolder) throws MessagingException {
        Folder[] folders = defaultFolder.list();
        for (Folder inFolder : folders) {
            LOGGER.info("开始处理-{} {} {}",folders.length, username, inFolder.getName());
            try {
                getMessages(inFolder);
                getAllFolders(inFolder);
            }catch (Exception e){
                LOGGER.info("文件夹出错 ", e);
            }
        }
    }

    private void getMessages(Folder folder) throws MessagingException {
        long maxTime = System.currentTimeMillis() + 86400000;

        folder.open(Folder.READ_ONLY);

        int start = 1;
        int end = folder.getMessageCount();
        int folderCount = end;
        int current = 1;
        int mid = (start + end) / 2;
        Long fetchTime = emailFetchSettingDO.getLastFetchTime();
        int type = 0;
        int times = 0;
        if (folderCount <= 0) {
            LOGGER.info("邮箱{},文件夹{},邮件数量为空:{},跳过", emailFetchSettingDO.getUsername(), folder.getName(), folderCount);
            return;
        }

        while (lastFetchTime != 0L) {
            times++;
            if (times >= 300) {
//                if (!folderName.contains("日历") && !folderName.contains("节假日")) {
//                    LOGGER.error("{},{},{},getMessage，疑似陷入死循环，人工check", emailFetchSettingDO.getUsername(), folderName, folderCount);
//                }
                return;
            }
            // 检查是否溢出
            if (mid > end || mid < 1) {
                LOGGER.info("{}-查找邮件溢出{},{}，人工检查", emailFetchSettingDO.getUsername(), mid, end);
                current = folderCount / 2;
                break;
            }
            // 检查邮件是否被删除
            Long sendTime = 0L;
            try {
                Message message = folder.getMessage(mid);
                if (message.getSentDate() != null) {
                    sendTime = message.getSentDate().getTime();
                }
                else {
                    String[] received = message.getHeader("Received");
                    try {
                        if (received != null && received.length > 0) {
                            String[] receivedTimes = received[0].split(",");
                            if (receivedTimes != null && receivedTimes.length > 0) {
                                Date receivedTime = null;
                                String tempDate = receivedTimes[receivedTimes.length - 1];
                                tempDate = tempDate.replace("\n", "");
                                tempDate = tempDate.replace("\r", "");

                                if (tempDate.length() < 40) {
                                    receivedTime = sdf.parse(tempDate);
                                } else {
                                    try {
                                        receivedTime = sdf.parse(tempDate.substring(tempDate.length() - 33));
                                    } catch (Exception e) {
                                        try {
                                            receivedTime = sdf.parse(tempDate.substring(tempDate.length() - 32));
                                        } catch (Exception e2) {
                                            receivedTime = sdf2.parse(tempDate.substring(tempDate.length() - 32));
                                        }
                                    }
                                }
                                if (receivedTime.getTime() < maxTime) {
                                    sendTime = receivedTime.getTime();
                                }
                            }
                        }
                    } catch (Exception e) {
                        LOGGER.warn("({})获取时间失败:{}", emailFetchSettingDO.getUsername(), e.getMessage());
                    }
                }
                if (sendTime == 0L) {
                    mid++;
                    continue;
                }
                LOGGER.info("mail:{}, sendTime:{}, start:{}, end:{}", emailFetchSettingDO.getUsername(), sendTime, start, end);
                if (sendTime > lastFetchTime) {
                    type = 1;
                    end = mid - 1;
                } else if (sendTime < lastFetchTime) {
                    type = 2;
                    start = mid + 1;
                } else {
                    current = mid + 1;
                    break;
                }
            } catch (NullPointerException | MessagingException e) {
                LOGGER.warn("({})查找邮件失败:{}", emailFetchSettingDO.getUsername(), e.getMessage());
                if (type == 1) {
                    end = mid - 1;
                } else if (type == 2) {
                    start = mid + 1;
                } else {
                    current = mid;
                    break;
                }
            }
//            if (sendTime > lastFetchTime) {
//                end = mid - 1;
//            } else if (sendTime < lastFetchTime) {
//                start = mid + 1;
//            } else {
//                current = mid + 1;
//                break;
//            }
            if (start >= end) {
                current = start + 1;
                break;
            }
            mid = (start + end) / 2;
        }
        Integer folderMailCount = folder.getMessageCount();

        Integer maxHandelCount = folderMailCount - current;

        LOGGER.info("{}开始抓取邮件:start:{},mailSize{}", emailFetchSettingDO.getUsername(), current, folderMailCount);
        Long sendDate = 0L;
        Integer mailCount = 0;
        try {
            if (current > 11) {
                current = current - 10;
            } else {
                current = 1;
            }
            for (int index = current; index <= folderMailCount; index++) {
                Message message = null;
                try {
                    LOGGER.info("开始获取{},index:{}", emailFetchSettingDO.getUsername(), index);
                    message = folder.getMessage(index);
                    if (emailFetchSettingDO.getUsername().contains("@timingbio.com")) {
                        message = new MimeMessage((MimeMessage) message);
                        LOGGER.info("转换message 类型 {} {}", emailFetchSettingDO.getUsername(), message.getSubject());
                    }
                    if (message == null || message.getSentDate() == null) {
                        continue;
                    }
                } catch (NullPointerException | MessagingException e) {
                    LOGGER.warn("({})邮件读取失败", emailFetchSettingDO.getUsername(), e);
                    continue;
                }

                sendDate = message.getSentDate().getTime();
                // 获取收件时间
                String[] received = message.getHeader("Received");
                try {
                    if (received != null && received.length > 0) {
                        String[] receivedTimes = received[0].split(",");

                        if (receivedTimes != null && receivedTimes.length > 0) {
                            String tempDate = receivedTimes[receivedTimes.length - 1];
                            tempDate = tempDate.replace("\n", "");
                            tempDate = tempDate.replace("\r", "");
                            // java.text.ParseException: Unparseable date: "(qmail 21312 invoked by uid 0); 25 Sep 2021 08:43:31 -0000"
                            if (emailFetchSettingDO.getUsername().contains("@timingbio.com") && tempDate.contains(";")) {
                                tempDate = tempDate.substring(tempDate.indexOf(";") + 2);
                            }
                            Date receivedTime = sdf.parse(tempDate);
                            if (receivedTime.getTime() < maxTime) {
                                sendDate = receivedTime.getTime();
                            }
                        }
                    }
                } catch (Exception e) {
                    LOGGER.info("JavaMailReceivederror,{}", emailFetchSettingDO.getUsername(), e);
                }
                if (sendDate < fetchTime) {
                    LOGGER.info("{}抓取时间小于设置时间{},发件时间{}", emailFetchSettingDO.getUsername(), fetchTime, sendDate);
                    continue;
                }
//                if (sendDate < redis???Time) {
//                    LOGGER.info("{}抓取时间小于redis时间{},发件时间{}", emailFetchSettingDO.getUsername(), fetchTime, sendDate);
//                    continue;
//                }
                // 更新最后抓取邮件时间
                RecruitmentHttpTools.updateEmailFetchTime(emailFetchSettingDO.getSettingId(), sendDate);

                String subject = "";
                String[] subjects = message.getHeader("subject");
                String subjectTmp = "";
                if (subjects != null && subjects.length >= 1) {
                    subjectTmp = subjects[0];
                }
                try {
                    if (emailFetchSettingDO.getUsername().contains("@qq.com") && !StringUtils.isEmpty(subjectTmp) && subjectTmp.contains("=?") && subjectTmp.contains("?=") && subjectTmp.length() >= 16) {
                        String subjectCharset = "";
                        // 取标题的前 15 个
                        String subTxt = subjectTmp.substring(0, 15);
                        int lastMark = subTxt.lastIndexOf("?");
                        if (lastMark > 0) {
                            subjectCharset = subjectTmp.substring(0, lastMark + 1);
                        }
                        LOGGER.info("邮箱{}编码为{}", emailFetchSettingDO.getUsername(), subjectCharset);
                        String[] subjectCharts = subjectTmp.split(subjectCharset.replaceAll("\\?", "\\\\?"));
                        for (String subjectChart : subjectCharts) {
                            if (StringUtils.isEmpty(subjectChart)) {
                                continue;
                            }
                            int subjectMdIndex = subjectChart.length();
                            if (subjectChart.contains("?=")) {
                                subjectMdIndex = subjectChart.lastIndexOf("?=") + 2;
                            }
                            String subjectMd = subjectCharset + subjectChart.substring(0, subjectMdIndex);
                            String subject2 = MimeUtility.decodeText(subjectMd);
                            Integer index1 = subjectChart.indexOf(subjectChart);
                            Integer index2 = subjectChart.length() + index1;
                            String tmpStart = "";
                            String tmpEnd = "";
                            if (index1 > 0) {
                                tmpStart = subjectChart.substring(0, index1);
                            }
                            if (index2 < subjectChart.length()) {
                                tmpEnd = subjectChart.substring(index2, subjectChart.length());
                            }
                            String subjectTitle = (tmpStart + subject2 + tmpEnd).replace("[SPAM]", "");
                            subject += subjectTitle;
                        }
                    } else {
                        subject = message.getSubject();
                    }
                    // 老的获取邮件标题的
                    if (StringUtils.isEmpty(subject)) {
                        String subjectTmp2 = StringUtils.substringBetween(message.getSubject(), "=?utf-8?b?", "?=");
                        if (!StringUtils.isEmpty(subjectTmp2)) {
                            String subjectMd = "=?utf-8?b?" + subjectTmp2 + "?=";
                            String subject2 = MimeUtility.decodeText(subjectMd);
                            Integer index1 = message.getSubject().indexOf("=?utf-8?");
                            Integer index2 = subjectMd.length() + index1;
                            String tmpStart = "";
                            String tmpEnd = "";
                            if (index1 > 0) {
                                tmpStart = message.getSubject().substring(0, index1);
                            }
                            if (index2 < message.getSubject().length()) {
                                tmpEnd = message.getSubject().substring(index2, message.getSubject().length());
                            }
                            subject = (tmpStart + subject2 + tmpEnd).replace("[SPAM]", "");
                        } else {
                            subject = message.getSubject();
                        }
                    }
                } catch (Exception e) {
                    LOGGER.info("{}邮箱标题获取失败{}", emailFetchSettingDO.getUsername(), e.getMessage(), e);
                }
                if (StringUtils.isEmpty(subject)) {
                    LOGGER.info("邮箱{},{},主题为空", emailFetchSettingDO.getUsername(), index);
                    continue;
                }
                // 检查发信人是否是可抓取渠道
                String from = getForm(message);
                ChannelTypeEnum channelTypeEnum = getChannelTypeByFrom(from);
                // 默认渠道为空
                if (channelTypeEnum == null) {
                    channelTypeEnum = getChannelTypeByCustom(from, subject, emailFetchSettingDO.getChannel());
                }
                if (channelTypeEnum == null) {
                    LOGGER.info("{}，未找到channelType，{}", message.getSubject(), from);
                    continue;
                }
                List<String> body = new ArrayList<>();
                try {
                    if (message.isMimeType("multipart/*")) {
                        body = EmailCrawler.parseMultipart((Multipart) message.getContent());
                    } else {
                        body.add((String) message.getContent());
                    }
                } catch (Exception e) {
                    LOGGER.info("{}获取邮件{}失败,{}", emailFetchSettingDO.getUsername(), message.getSubject(), e.getMessage(), e);
                    if (e instanceof FolderClosedException) {
                        LOGGER.info("文件夹关闭，暂时跳出");
                        return;
                    }
                    continue;
                }
                if (body.isEmpty()) {
                    continue;
                }
//                LOGGER.info("{}解析到邮件:{}<{}>(index:{}),{}", emailFetchSettingDO.getUsername(), message.getSubject(), from, index, folderName);
//                EmailMessageDO messageDO = new EmailMessageDO();
//                messageDO.setSubject(subject);
//                messageDO.setChannelType(channelTypeEnum.getValue());
//                messageDO.setChannelId(channelTypeEnum.getChannelId());
//                messageDO.setSendDate(sendDate);
//                messageDO.setFrom(from);
//                // 判断库里面是否存在该简历
//                String md5 = MD5Util.md5(messageDO.getSubject());
//                String emailMd5 = iTrEmailJobService.queryTrEmailJobId(emailFetchSettingDO.getUsername(), channelTypeEnum.getValue(), sendDate, md5);
//                if (!StringUtils.isBlank(md5) && !StringUtils.isBlank(emailMd5)) {
//                    LOGGER.info("{}，{}已经存在{}", emailFetchSettingDO.getUsername(), messageDO.getSubject(), sendDate);
//                    continue;
//                }
                String content = EmailCrawler.encodeBody(body.get(body.size() - 1));
                String contentKey = OssFile.uploadFile(content);


//                System.out.println(content);
//                if (ChannelTypeEnum.KQ36.getValue().equals(channelTypeEnum.getValue())) {
//                    content = content.replace("https://img.kq36.com.cn/weixin_img.jpg", "");
//                    content = content.replace("https://img.kq36.com.cn/app_img.jpg", "");
//                }
//                String fileKey = iFileService.uploadString(content);
//                messageDO.setBody(fileKey);
//                LOGGER.info("{}开始下载文件{}", emailFetchSettingDO.getUsername(), messageDO.getSubject());
                String attachmentKey = "";
                try {
                    String filePath = EmailCrawler.parseAttachment(message, subject, emailFetchSettingDO.getUsername(), true, channelTypeEnum.getValue());
                    LOGGER.info("附件key {}", filePath);
                    if (StringUtils.isNotEmpty(filePath)){
                        attachmentKey = OssFile.uploadFile(new File(filePath));
                    }
                } catch (Exception e) {
                    LOGGER.info("{},{},附件下载失败{}", emailFetchSettingDO.getUsername(), subject, e.getMessage(), e);
                }
                // 保存邮件
                RecruitmentHttpTools.saveMailInfo(emailFetchSettingDO.getUsername(), from, sendDate, contentKey, subject, attachmentKey, channelTypeEnum.getValue(), System.currentTimeMillis());

//                if(messageDO.getAttachment() != null){
//                    File attachement  = new File(messageDO.getAttachment());
//                    String attachmentKey = OssFile.uploadFile(attachement);
//                    messageDO.setAttachment(attachmentKey);
//                } else {
//                    // 自定义渠道没有附件
//                    if (ChannelTypeEnum.CUSTOM == channelTypeEnum) {
//                        LOGGER.info("自定义渠道没有附件,{}", emailFetchSettingDO.getUsername(), subject);
//                        continue;
//                    }
//                }
//                LOGGER.info("{}下载文件结束{}", emailFetchSettingDO.getUsername(), messageDO.getSubject());
//                messageDO.setReceiver(emailFetchSettingDO.getUsername());
//                // 发送解析消息
//                EmailJobDO emailJobDO = iTrEmailJobService.insertEmailJob(messageDO,pageDO.getRequestDO().getTaskId(), md5);
//                spider_logger.info(JsonUtil.toJson(emailJobDO));
//                RequestDO requestDO = pageDO.getRequestDO();
//                requestDO.setUrl(from);
//                messageDO.setEmailJobId(emailJobDO.getId());
//                requestDO.setMeta(JsonUtil.toJson(messageDO));
//                requestDO.setType(ParserTypeEnum.RESUME_DETAIL.getValue().toString());
//                requestDO.setEmailjobId(emailJobDO.getId());
//                pageDO.setRequestDO(requestDO);
//                pageDO.setPageKey(fileKey);
//                mailCount++;
//                IEmailContentParser parser = EmailParser.parserFactory(channelTypeEnum);
//                if (!parser.shouldParse(messageDO.getSubject()) ) {
//                    String request = JsonUtil.toJson(requestDO);
//                    iEmailjobretryService.insertRetryJob(requestDO.getRetryId(),emailJobDO.getId(),channelTypeEnum.getTargetName(),request,"主题不在配置中", RetryTypeEnum.WAIT.getValue(), ErrorTypeEnum.SUBJECT_UNDEFIND.getValue(), 0);
//                    LOGGER.info("根据邮件名称不需要进行抓取:{},渠道{}", message.getSubject(), channelTypeEnum.getTargetName());
//                    continue;
//                }
//                if (ChannelTypeEnum.LAGOU.getValue().equals(channelTypeEnum.getValue())){
//                    commonRedisDAO.saveHashValue(LockConstant.LAGOU_EMAIL_KEYS, emailFetchSettingDO.getUsername(), "0");
//                    commonRedisDAO.saveHashValue(emailFetchSettingDO.getUsername(), String.valueOf(requestDO.getEmailjobId()), "0");
//                } else {
//                iMessageService.sendPage(pageDO);
//                }
            }

        } catch (Exception e) {

            LOGGER.info("{}javaMail邮件列表获取失败{}", emailFetchSettingDO.getUsername(), e.getMessage(), e);
        } finally {
            folder.close();
        }
    }

    private ChannelTypeEnum getChannelTypeByCustom(String from, String subject, List<ChannelTO> channel) {
        LOGGER.info("getChannelTypeByCustom {} {} {}", from, subject, JsonUtil.toJson(channel));
        if (org.apache.commons.lang.StringUtils.isEmpty(from)) {
            return null;
        }
        for (ChannelTO customChannelDO : channel) {
                if (StringUtils.isNotEmpty(customChannelDO.getOutBoxs())) {
                try {
                    for (String outBox : customChannelDO.getOutBoxs().split(";")) {
                        LOGGER.info("outBox {} {} {}", outBox, from, subject);
                        // 邮箱满足
                        // 如果 配置的发件箱是 【recruitment@xinrenxinshi.com】 关键词为 【全部】 那么默认抓取该邮箱下全部有附件的简历
                        if (Objects.equals("recruitment@xinrenxinshi.com", outBox) && Objects.equals("全部", customChannelDO.getKeyWords().split(",")[0])) {
                            ChannelTypeEnum channelTypeEnum = ChannelTypeEnum.CUSTOM;
                            channelTypeEnum.setChannelId(customChannelDO.getChannelType());
                            return channelTypeEnum;
                        }
                        if (from.equals(outBox) || Objects.equals("recruitment@xinrenxinshi.com", outBox)) {
                            for (String keyWords : customChannelDO.getKeyWords().split(",")){
                                // 关键词满足
                                if (StringUtils.isNotEmpty(keyWords) && subject.contains(keyWords)) {
                                    ChannelTypeEnum channelTypeEnum = ChannelTypeEnum.CUSTOM;
                                    channelTypeEnum.setChannelId(customChannelDO.getChannelType());
                                    return channelTypeEnum;
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    LOGGER.info("JSONArray 转换错误{}" , JsonUtil.toJson(customChannelDO), e);
                }
            }
        }
        return null;
    }

    private void updateProgressRate(EmailFetchSettingDO username, Long sendDate) {
        LOGGER.info("");

    }

    static List<String> parseMultipart(Multipart multipart) throws Exception {
        int count = multipart.getCount();
        List<String> content = new ArrayList<>();
        String patternTxt = "[\\u4e00-\\u9fa5]";
        for (int index = 0; index < count; index++) {
            BodyPart part = multipart.getBodyPart(index);
            if (part.isMimeType("multipart/*")) {
                content.addAll(parseMultipart((Multipart) part.getContent()));
            } else if (part.isMimeType("text/*")) {
                String string = (String) part.getContent();
                Pattern p = Pattern.compile(patternTxt);
                Matcher m = p.matcher(string);
                if (!m.find()) {
                    string = new String(string.getBytes("ISO8859_1"), "GBK");
                    string = MimeUtility.decodeText(string);
                }
                content.add(string);
            }
        }
        return content;
    }

    public Store getJavaMailInstance(EmailFetchSettingDO settingDO) throws MessagingException, InterruptedException {
        LOGGER.info("进入pop3、imap邮箱登录" + settingDO.getHost());
//        LOGGER.info("emailSettingDO {}", JsonUtil.toJson(settingDO));
        Properties props = new Properties();
        props.put("http.proxySet","true");//设置代理主机参数
//        props.put("socksProxyHost","127.0.0.1");
//        props.put("socksProxyPort","1080");
        MailProtocolEnum mailProtocolEnum = MailProtocolEnum.findByValue(settingDO.getProtocol());
        try {
            props.setProperty("mail.store.protocol", mailProtocolEnum.getDesc());
            props.setProperty("mail." + mailProtocolEnum.getDesc() + ".host", settingDO.getHost());
            props.setProperty("mail." + mailProtocolEnum.getDesc() + ".port", settingDO.getPort().toString());
            props.setProperty("mail." + mailProtocolEnum.getDesc() + ".connectiontimeout", "30000");
            props.setProperty("mail." + mailProtocolEnum.getDesc() + ".timeout", "40000");


            // 读取附件很慢问题修复
//            if (Objects.equals(MailProtocolEnum.IMAP.getValue(), mailProtocolEnum.getValue())) {
//                props.setProperty("mail.imap.partialfetch", "false");
//                props.setProperty("mail.imaps.partialfetch", "false");
//            }

            if (settingDO.getSsl()) {
                // 阿里云邮箱不加这个会报 SSL Exception, 其他邮箱不知道能不能加，先做特殊处理
//                if (settingDO.getHostname().contains("aliyun")) {
//                    LOGGER.info("aliyun 邮箱属性设置{}", emailFetchSettingDO.getUsername());
//                    props.setProperty("mail." + protocol + ".starttls.enable", "true");
//                    props.setProperty("mail."+protocol+".auth", "true");
//                    props.setProperty("mail." + protocol + ".auth.plain.disable", "true");
//                }
                props.setProperty("mail." + mailProtocolEnum.getDesc() + ".ssl.enable", "true");
                props.setProperty("mail." + mailProtocolEnum.getDesc() + ".ssl.trust", "*");
                props.setProperty("mail." + mailProtocolEnum.getDesc() + ".socketFactory.class", "javax.net.ssl.SSLSocketFactory");
                props.setProperty("mail." + mailProtocolEnum.getDesc() + ".socketFactory.fallback", "false");
                props.setProperty("mail." + mailProtocolEnum.getDesc() + ".socketFactory.port", settingDO.getPort().toString());

                System.out.println("设置ssl");
            }

            String user = settingDO.getUsername();
//            if (settingDO.getUserType() != null && settingDO.getUserType() == 1) {
//                user = StringUtils.substringBefore(emailFetchSettingDO.getUsername(), "@");
//            }
            final String email = user;
            final String password = settingDO.getPassword();
            // 登录到需要抓取的邮箱
            Authenticator auth = new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(email, password);
                }
            };
            Session session = Session.getInstance(props, auth);//邮件基本会话，必备，用它来共享信息
            if (Objects.equals(MailProtocolEnum.IMAP.getValue(), mailProtocolEnum.getValue()) && (email.contains("@126.com") || email.contains("@163.com") || email.contains("@timingbio.com"))) {

                IMAPStore store = (IMAPStore) session.getStore("imap");
                store.connect(email, password);
                HashMap imapMap = new HashMap();
                //带上IMAP ID信息，由key和value组成，例如name，version，vendor，support-email等。
                imapMap.put("name", "foxmail");
                imapMap.put("version", "1.0.0");
                imapMap.put("vendor", "foxmailClient");
                imapMap.put("support-email", email);
                store.id(imapMap);
                return store;
            } else {
                Store store = session.getStore(mailProtocolEnum.getDesc());
                // 防止登录请求 被 drop
                int maxLoginRetired = 3;
                while (maxLoginRetired > 0) {
                    maxLoginRetired--;
                    try {
                        store.connect(emailFetchSettingDO.getHost(), emailFetchSettingDO.getPort(), email, password);   //通过Store类可以访问邮箱中的folder类
                        break;
                    } catch (Exception e) {
                        String message = e.getMessage();
                        if (message != null && message.contains("Connection dropped") && maxLoginRetired > 0) {
//                            LOGGER.info("drop retried {}", emailFetchSettingDO.getUsername());
                            Thread.sleep(3000);
                            continue;
                        } else {
                            throw e;
                        }
                    }
                }
                return store;
            }
        } catch (Exception e) {
            String exceptionName = e.getClass().getName();
            Integer emailUsable = 0;
            if (exceptionName.contains("AuthenticationFailed")) {
//                emailUsable = EmailUsableEnum.PASSWORD_ERROR.getValue();
                if (emailFetchSettingDO.getSettingId() != null){
                    RecruitmentHttpTools.updateEmailValid(emailFetchSettingDO, 1);
                }
                LOGGER.info("{}可能改密码了,人工验证下", emailFetchSettingDO.getUsername());
                throw e;
            }
//            spider_logger.info(JsonUtil.toJson(new MailErrorDO(emailFetchSettingDO.getUsername(), emailUsable)));
////            spider_logger.info("邮箱采集出错:{},错误类型:{},调度ID:{},任务ID:{},错误时间:{}", emailFetchSettingDO.getUsername(), emailUsable, settingDO.g, mailBoxId, TimeUtils.getTimeForSecond());
//            iEmailService.updateEamilUsable(emailFetchSettingDO.getUsername(), emailUsable, e.getMessage());
            LOGGER.info("JavaMail邮箱{}({})登录失败", emailFetchSettingDO.getUsername(), mailProtocolEnum.getDesc(), e);
            return null;
        }
    }

    private static File concatImg2Html(Multipart multipart) throws MessagingException, IOException {
        int count = multipart.getCount();
        File resumeFile = null;
        String fileName = "";
        String suffix = "";
        String resumeHtml = "";
        String imgBase64 = "";
        for (int index = 0; index < count; index++) {
            BodyPart part = multipart.getBodyPart(index);
            if (part.getFileName() != null) {
                fileName = MimeUtility.decodeText(part.getFileName());
            }

            if (part.isMimeType("application/octet-stream") || part.isMimeType("application/msword") || part.isMimeType("application/pdf") || part.isMimeType("application/wps-writer")
                    || part.isMimeType("image/jpeg") || part.isMimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document") || part.isMimeType("text/html")) {
                // 附件
                InputStream stream = part.getInputStream();
                UniversalDetector detector = new UniversalDetector(null);

                byte[] sss = getBytes(stream);
                detector.handleData(sss, 0, sss.length);
                detector.dataEnd();
                String charset = detector.getDetectedCharset();

                if (fileName.lastIndexOf(".") > 0) {
                    suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
                }
                if (!org.apache.commons.lang.StringUtils.isBlank(suffix)) {
                    suffix = suffix.replace("?=", "");
                    FileTypeEnum typeEnum = FileTypeEnum.findSuffix(suffix);
                    if (typeEnum == FileTypeEnum.OTHER) {
                        suffix = "";
                    }
                }

//                        byte[] bytes = IOUtils.readFully(stream, stream.read());
                if (suffix.equals("html")) {
                    resumeHtml = new String(sss, charset);
                    resumeFile = FileUtil.createTempleFile(sss, "html");
                }
                if (suffix.equals("jpg")) {
                    LOGGER.info("将前程无忧头像拼接到html内");
                    imgBase64 = Base64.getMimeEncoder().encodeToString(sss);


                }
                if (!resumeHtml.equals("") && resumeHtml.contains(fileName) && !imgBase64.equals("")) {
                    Document document = Jsoup.parse(resumeHtml);
                    Elements headImg = document.select("img[src=" + fileName + "]");
                    imgBase64 = "data:image/jpg;base64," + imgBase64;
                    headImg.get(0).attr("src", imgBase64);
                    headImg.get(0).attr("wu-you-portrait", "yes");
                    File file = FileUtil.createTempleFile(document.toString().getBytes(StandardCharsets.UTF_8), "html");
                    LOGGER.info("拼接地址 {}", file.getAbsolutePath());
                    return file;
                }

            } else {
            }
        }
        return resumeFile;
    }

    public static byte[] getBytes(InputStream is) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        for (int b = is.read(); b >= 0; b = is.read()) baos.write(b);
        return baos.toByteArray();
    }

    /**
     * 解析附件
     *
     * @param message
     * @return
     * @throws Exception
     */
    static String parseAttachment(Message message, String subject, String email, boolean isChange, Integer channelType) throws Exception {
        if (!message.isMimeType("multipart/*")) {
            return null;
        }
        Multipart multipart = (Multipart) message.getContent();
        int count = multipart.getCount();
        String fileName = "";
        String suffix = "";
        LOGGER.info("邮箱{},{},附件数量{}", email, subject, count);
        File resumeFile = null;
        File imgFile = null;
        LOGGER.info("emailMessageDO {}", channelType);
        if (channelType.equals(ChannelTypeEnum.WUYOU.getValue())) {
            File file = concatImg2Html(multipart);
            LOGGER.info("拼接File {} {}", subject, file);
            if (file != null) {
                LOGGER.info("头像拼接成功 " + file.getAbsolutePath());

                return file.getAbsolutePath();
            }
        }
        for (int index = 0; index < count; index++) {
            BodyPart part = multipart.getBodyPart(index);
            if (part.isMimeType("application/octet-stream") || part.isMimeType("application/msword") || part.isMimeType("application/pdf") || part.isMimeType("application/wps-writer")
                    || part.isMimeType("image/jpeg") || part.isMimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
                // 附件
                InputStream stream = part.getInputStream();
                if (part.getFileName() != null) {
                    fileName = MimeUtility.decodeText(part.getFileName());
                    try {
                        int charSetIndex = 0;
                        if (fileName.contains("=?UTF-8")) {
                            charSetIndex = fileName.lastIndexOf("=?UTF-8");
                        } else if (fileName.contains("=?utf-8")) {
                            charSetIndex = fileName.lastIndexOf("=?utf-8");
                        } else if (fileName.contains("=?gb2312")) {
                            charSetIndex = fileName.lastIndexOf("=?gb2312");
                        } else if (fileName.contains("=?gbk")) {
                            charSetIndex = fileName.lastIndexOf("=?gbk");
                        } else if (fileName.contains("=?GBK")) {
                            charSetIndex = fileName.lastIndexOf("=?GBK");
                        }
                        if (charSetIndex > 0 && charSetIndex < fileName.length()) {
                            String endTxt = fileName.substring(charSetIndex, fileName.length());
                            String endFileName = MimeUtility.decodeText(endTxt);
                            String firstFileName = fileName.substring(0, charSetIndex);
                            fileName = firstFileName + endFileName;
                        }
                    } catch (Exception e) {
                        LOGGER.info("{},解析文件名处理错误", subject, e);
                    }
                }
                LOGGER.info("{},{}下载文件{}大小{}", subject, fileName, index, part.getSize());
                File file;
                if (fileName.lastIndexOf(".") > 0) {
                    suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length());
                }
                if (!org.apache.commons.lang.StringUtils.isBlank(suffix)) {
                    suffix = suffix.replace("?=", "");
                    FileTypeEnum typeEnum = FileTypeEnum.findSuffix(suffix);
                    if (typeEnum == FileTypeEnum.OTHER) {
                        suffix = "";
                    }
                }
                if (!org.apache.commons.lang.StringUtils.isBlank(suffix)) {
                    file = File.createTempFile("attachment_", "." + suffix);
                } else {
                    file = File.createTempFile("attachment_", "_email");
                }
                try {
                    FileUtils.copyInputStreamToFile(stream, file);
//                    emailMessageDO.setAttachment(file.getAbsolutePath());
                    LOGGER.info("{}文件大小{}", subject, file.length());
                    return file.getAbsolutePath();
                } catch (Exception e) {
                    LOGGER.info("{}文件下载失败{},{}", subject, fileName, e.getMessage(), e);
                }
            } else {
                LOGGER.info("{}，{},不支持的文件类型,文件类型为{}", subject, email, part.getContentType());
            }
        }
        return null;
    }


    static ChannelTypeEnum getChannelTypeByFrom(String from) {
        if (StringUtils.isEmpty(from)) {
            return null;
        }
        ChannelTypeEnum channelTypeEnum = null;
        if (from.contains("zhaopinmail.com") || from.contains("zhaopin.com") || from.contains("test112@bigsaas.cn")) {
            channelTypeEnum = ChannelTypeEnum.ZHILIAN;
        } else if (from.contains("quickmail.51job.com") || from.contains("test113@bigsaas.cn")) {
            channelTypeEnum = ChannelTypeEnum.WUYOU;
        } else if (from.contains("lietou-edm.com") || from.contains("test114@bigsaas.cn")) {
            channelTypeEnum = ChannelTypeEnum.LIEPIN;
        } else if (from.contains("mail.dxy.cn")) {
            channelTypeEnum = ChannelTypeEnum.DINGXIANG;
        } else if (from.contains("kq36.com")) {
            channelTypeEnum = ChannelTypeEnum.KQ36;
        } else if (from.contains("lagoujobs.com") || from.contains("email.lagou.com")) {
            channelTypeEnum = ChannelTypeEnum.LAGOU;
        } else if (from.contains("send.ganji.com") || from.contains("zp.58.com")) {
            channelTypeEnum = ChannelTypeEnum.WUBA;
        } else if (from.contains("shoudurc.com")) {
            channelTypeEnum = ChannelTypeEnum.SDRC;
        } else if (from.contains("maimai.cn")) {
            channelTypeEnum = ChannelTypeEnum.MAIMAI;
        } else if (from.contains("bosszhipin.com") || from.contains("notice.zhipin.com") || from.contains("service.zhipin.com") ||
                from.contains("kanzhun.com") || from.contains("test111@bigsaas.cn")) {
            channelTypeEnum = ChannelTypeEnum.BOSS;
        } else if (from.contains("shixiseng.com")) {
            channelTypeEnum = ChannelTypeEnum.SHIXI;
        } else if (from.contains("poster.bczp.cn")) {
            channelTypeEnum = ChannelTypeEnum.SHANGTOU;
        } else if (from.contains("cms.job001.cn")) {
            channelTypeEnum = ChannelTypeEnum.GUOJIRENCAI;
        } else if (from.contains("notice.buildhr.com")) {
            channelTypeEnum = ChannelTypeEnum.BUILDHR;
        } else if (from.contains("jobcn.com")) {
            channelTypeEnum = ChannelTypeEnum.ZHUOBO;
        } else if (from.contains("827132927@qq.com")) {
            channelTypeEnum = ChannelTypeEnum.ZHUOBO;
        } else if (from.contains("reply.veryeast.cn")) {
            channelTypeEnum = ChannelTypeEnum.ORIENTAL;
        } else if (from.contains(".job5156.com")) {
            channelTypeEnum = ChannelTypeEnum.ZHITONG;
        } else if (from.contains("bczp.cn") || from.contains("test115@bigsaas.cn")) {
            channelTypeEnum = ChannelTypeEnum.DAFOSHANPERSONNEL;
        } else if (from.contains("notify.goodjobs.cn")) {
            channelTypeEnum = ChannelTypeEnum.XINAN_TALENT;
        } else if (from.contains("feedback@mta.myyjs.com")) {
            channelTypeEnum = ChannelTypeEnum.GRADUATE;
        } else if (from.contains("xumuzx.com")) {
            channelTypeEnum = ChannelTypeEnum.XUMU_TALENT;
        } else if (from.contains("xumurc.com")) {
            channelTypeEnum = ChannelTypeEnum.MU_TONG_TALENT;
        } else if (from.contains("poster@notice.chenhr.com")) {
            channelTypeEnum = ChannelTypeEnum.CHENHR;
        } else if (from.contains("bjx.com.cn") || from.contains("wmm1996528@qq.com")) {
            channelTypeEnum = ChannelTypeEnum.BEIJIXING;
        }
        // 如果删除默认渠道
//        if (channelTypeEnum != null && !defaultChannel.containsKey(channelTypeEnum.getValue())) {
//            channelTypeEnum = null;
//        }

        return channelTypeEnum;
    }


    /**
     * 获取发件人
     *
     * @param message
     * @return
     * @throws Exception
     */
    static String getForm(Message message) throws Exception {
        try {
            Address[] addresses = message.getFrom();
            if (addresses == null || addresses.length < 1) {
                return getSender(message);
            }
            InternetAddress address = (InternetAddress) addresses[0];
            return address.getAddress();
        } catch (Exception e) {
            return getSender(message);
        }
    }

    /**
     * 获取代发
     *
     * @param message
     * @return
     * @throws Exception
     */
    static String getSender(Message message) throws Exception {
        try {
            String[] sender = message.getHeader("sender");
            if (sender == null || sender.length < 1) {
                sender = message.getHeader("X-QQ-ORGSender");
            }
            if (sender == null || sender.length < 1) {
                return null;
            }
            return sender[0];
        } catch (Exception e) {
            return null;
        }
    }

    static String encodeBody(String body) throws Exception {
        if (isStringValidInCharset(body, "utf-8")) {
            return new String(body.getBytes("utf-8"), "utf-8");
        } else if (isStringValidInCharset(body, "gb2312")) {
            return new String(body.getBytes("gb2312"), "utf-8");
        } else {
            return null;
        }
    }

    static Boolean isStringValidInCharset(String body, String charset) throws Exception {
        byte[] bytes = body.getBytes(charset);
        String str = new String(bytes, charset);
        return str.equals(body);
    }

    public static void main(String[] args) throws MessagingException, InterruptedException {
        EmailFetchSettingDO emailFetchSettingDO = new EmailFetchSettingDO();
        emailFetchSettingDO.setHost("pop.exmail.qq.com");
        emailFetchSettingDO.setPort(995);
        emailFetchSettingDO.setSsl(true);
        emailFetchSettingDO.setPassword("Lucky920106");
        emailFetchSettingDO.setUsername("shidehong_jianli@qijiayoudao.com");
        emailFetchSettingDO.setProtocol(0);
        emailFetchSettingDO.setLastFetchTime(1635782400000L);
        EmailCrawler emailCrawler = new EmailCrawler(emailFetchSettingDO);
        Store store = emailCrawler.getJavaMailInstance(emailFetchSettingDO);
        emailCrawler.fetchAllEmail(store);
    }
}
